<template>
  <a-modal
    :width="width"
    wrapClassName="draggable-modal"
    :open="open"
    :maskClosable="false"
    :footer="null"
    @cancel="onCancel"
  >
    <!-- title 区域用于点击拖拽 -->
    <template #title>
      <div ref="modalTitleRef" class="title">{{ title }}</div>
    </template>

    <div class="modal-content">
      <a-spin :spinning="isLoading">
        <!-- 表单：修复model绑定，补充校验规则 -->
        <a-form 
          ref="formRef" 
          :model="formData" 
          :rules="formRules" 
          :labelCol="labelCol" 
          :wrapperCol="wrapperCol"
        >
          <a-form-item label="" name="authorization">
            <!-- a-tree 配置：使用 default-expand-all，绑定 expandedKeys -->
            <a-tree
              v-model:selectedKeys="selectedKeys"
              v-model:checkedKeys="checkedKeys"
              v-model:expandedKeys="expandedKeys"
              default-expand-all
              checkable
              check-strictly
              :tree-data="treeData"
              @check="handleTreeCheck"
            >
              <template #title="{ title, key }">
                <span>{{ title }}</span>
              </template>
            </a-tree>
          </a-form-item>
        </a-form>
      </a-spin>
    </div>

    <!-- 表单按钮：移除htmlType="submit"，避免默认提交行为 -->
    <div class="modal-footer">
      <a-form-item class="form-item-buttons">
        <a-flex justify="center" :gap="16">
          <a-button type="primary" @click="onFinish">确定</a-button>
          <a-button @click="onCancel">取消</a-button>
        </a-flex>
      </a-form-item>
    </div>

    <!-- 自定义渲染 实现拖拽效果 -->
    <template #modalRender="{ originVNode }">
      <div :style="transformStyle">
        <component :is="originVNode" />
      </div>
    </template>
  </a-modal>
</template>

<script setup lang="ts">
  import { ref, reactive, computed, watch, watchEffect, type CSSProperties } from 'vue';
  import { useDraggable } from '@vueuse/core';
  import { message } from 'ant-design-vue';
  import { bizApi } from '@/api/biz';
  import type { TreeProps, TreeDataNode, ExpandedKeys } from 'ant-design-vue';

  // ----------------------- 1. 类型定义 -----------------------
  // 树形节点类型（适配后端返回的module_id/module_name）
  interface TreeItem {
    module_id: number | string; // 后端返回的模块ID
    module_name: string;        // 后端返回的模块名称
    children?: TreeItem[];      // 子模块
    title?: string;             // 树形组件显示文本（转换后）
    key?: string;               // 树形组件唯一标识（转换后）
    disabled?: boolean;         // 是否禁用（已授权模块）
  }

  // 表单数据类型
  interface FormData {
    authorization: string[]; // 已授权模块的key集合（字符串类型，适配组件）
    roleId?: number | string; // 新增：关联的角色ID（授权需绑定角色）
  }

  // ----------------------- 2. 基础配置 -----------------------
  const title = ref('角色授权');
  const open = ref(false);
  const isLoading = ref(false);
  const formRef = ref();
  const width = ref(600); // 弹窗宽度

  // 表单布局
  const labelCol = { style: { width: '120px' } };
  const wrapperCol = { span: 24 };

  // ----------------------- 3. 表单数据与校验 -----------------------
  // 表单数据：修复ref为reactive，确保双向绑定正常
  const formData = reactive<FormData>({
    authorization: [],
    roleId: undefined // 初始为空，显示弹窗时传入
  });

  // 树形组件选中的节点key（单选/多选选中，非勾选）
  const selectedKeys = ref<string[]>([]);
  // 树形组件勾选的节点key（用于授权）
  const checkedKeys = ref<string[]>([]);
  // 树形组件展开的节点key
  const expandedKeys = ref<string[]>([]);

  // 表单校验规则：授权模块必选
  const formRules = reactive({
    authorization: [
      { 
        required: true, 
        message: '请至少选择一个授权模块', 
        trigger: 'change' 
      }
    ]
  });

  // ----------------------- 4. 树形数据处理 -----------------------
  // 1. 后端返回的原始菜单树（响应式，避免直接赋值数组）
  const menuTree = ref<TreeItem[]>([]);

  // 2. 转换树形数据格式（适配antd组件：module_id→key，module_name→title，确保层级结构正确）
  const transformTreeData = (array?: TreeItem[]): TreeDataNode[] => {
    if (!Array.isArray(array) || array.length === 0) return [];
    
    return array.map(item => {
      const newItem: TreeDataNode = {
        title: item.module_name, // 树形显示的文本（必传，确保节点正常显示）
        key: String(item.module_id), // 组件唯一key（转为字符串，避免数字ID问题）
        children: item.children ? transformTreeData(item.children) : undefined, // 递归处理子节点，确保层级完整
      };
      return newItem;
    });
  };

  // 3. 树形数据（依赖menuTree加载完成后生成，确保展开时数据已存在）
  const treeData = computed<TreeDataNode[]>(() => {
    return transformTreeData(menuTree.value);
  });

  // 主动展开所有节点的方法
  const expandAllNodes = () => {
    const allKeys: string[] = [];
    const collectKeys = (nodes: TreeDataNode[]) => {
      nodes.forEach(node => {
        allKeys.push(node.key);
        if (node.children) {
          collectKeys(node.children);
        }
      });
    };
    collectKeys(treeData.value);
    expandedKeys.value = allKeys;
  };

  // ----------------------- 5. 业务接口与数据加载 -----------------------
  // 业务请求参数（固定获取总后台所有级别模块）
  const getParams = ref({
    module_type: 2,        // 总后台模块
    module_level_type: 3   // 所有级别模块
  });

  // 业务接口方法名
  const getAction = 'base.manage.module.ServiceImpl.listTreeByModuleType';

  // 加载模块树形数据（确保数据加载完成后，组件再渲染，避免展开失效）
  async function getDataInfo() {
    isLoading.value = true;
    try {
      // 调用接口（注意：httpList参数应为getParams.value，非getParams）
      const result = await bizApi.httpList(getAction, getParams.value);
      // 赋值原始数据（避免Object.assign覆盖数组响应式）
      menuTree.value = Array.isArray(result) ? result : [];
      // 数据加载完成后，主动展开所有节点
      expandAllNodes();
    } catch (error: any) {
      message.error(error?.message || '模块数据加载失败');
      menuTree.value = [];
    } finally {
      isLoading.value = false;
    }
  }

  // ----------------------- 6. 树形事件处理 -----------------------
  // 树形节点勾选事件：同步勾选状态到表单授权数据
  const handleTreeCheck = (checkedKeysObj: { checked: string[]; halfChecked: string[] }) => {
    // 将勾选的节点key赋值给表单的authorization，用于表单校验和提交
    console.log("handleTreeCheck", checkedKeysObj.checked);
    formData.authorization = checkedKeysObj.checked;
  };


  // ----------------------- 7. 弹窗控制与表单提交 -----------------------
  // 弹窗显示：接收角色ID和初始授权数据（编辑场景）
  const show = (roleId: number | string, initAuthData: string[] = []) => {
    // 重置表单
    formData.roleId = roleId; // 绑定当前授权的角色ID
    formData.authorization = initAuthData; // 初始已授权模块
    checkedKeys.value = initAuthData; // 初始勾选已授权的模块
    formRef.value?.resetFields();
    
    // 显示弹窗并加载模块数据（数据加载完成后，主动展开所有节点）
    open.value = true;
  };
  /* 监听 props.open = true 时，调用 onOpen 方法 并传递 recordId */
  watch(() => open.value, (val) => {
    if (val === true) {
      getDataInfo();
    }
  })

  // 弹窗关闭：重置状态
  const onCancel = () => {
    open.value = false;
    // 延迟重置，避免关闭动画卡顿
    setTimeout(() => {
      formData.authorization = [];
      formData.roleId = undefined;
      checkedKeys.value = [];
      selectedKeys.value = [];
      expandedKeys.value = [];
    }, 300);
  };

  // 表单提交：调用授权接口
  const onFinish = async () => {
    try {
      // 1. 表单校验
      await formRef.value.validate();
      console.log('formData', formData);
      
      // 2. 校验角色ID（必传）
      if (!formData.roleId) {
        message.error('请选择需要授权的角色');
        return;
      }

      // 3. 提交参数（适配后端接口格式）
      const submitParams = {
        role_id: formData.roleId, // 角色ID
        role_permission: formData.authorization // 已授权模块ID集合
      };

      isLoading.value = true;
      // 调用授权接口（替换为实际授权接口的action）
      const result = await bizApi.httpSave(
        'base.manage.role.ServiceImpl.update',
        submitParams
      );

      // 4. 提交成功
      message.success(result?.sub_message || '角色授权成功');
      onCancel(); // 关闭弹窗
      // 通知父组件刷新数据（如需）
      emits('dataReload');
    } catch (error: any) {
      // 5. 错误处理
      message.error(error?.message || '角色授权失败，请重试');
      console.error('授权错误：', error);
    } finally {
      isLoading.value = false;
    }
  };

  // ----------------------- 8. 组件通信 -----------------------
  // 事件发射：授权成功通知父组件
  const emits = defineEmits<{
    dataReload: [];
  }>();

  // 暴露方法给父组件（显示弹窗）
  defineExpose({
    show
  });

  // ----------------------- 9. 拖拽逻辑优化 -----------------------
  const modalTitleRef = ref();
  const { x, y, isDragging } = useDraggable(modalTitleRef);

  // 拖拽起始位置
  const startX = ref(0);
  const startY = ref(0);
  const startedDrag = ref(false);

  // 当前变换的坐标
  const transformX = ref(0);
  const transformY = ref(0);

  // 拖拽前的变换坐标
  const preTransformX = ref(0);
  const preTransformY = ref(0);

  // 拖拽区域的边界矩形
  const dragRect = ref({ left: 0, right: 0, top: 0, bottom: 0 });

  // 监听x、y坐标变化，更新拖拽起始位置和边界信息
  watch([x, y], () => {
    if (!startedDrag.value) {
      startX.value = x.value;
      startY.value = y.value;

      const bodyRect = document.body.getBoundingClientRect();
      const titleRect = modalTitleRef.value.getBoundingClientRect();
      dragRect.value.right = bodyRect.width - titleRect.width;
      dragRect.value.bottom = bodyRect.height - titleRect.height;

      preTransformX.value = transformX.value;
      preTransformY.value = transformY.value;
    }
    startedDrag.value = true;
  });
  watch(isDragging, () => {
    if (!isDragging) {
      startedDrag.value = false;
    }
  });

  // 计算拖拽过程中的变换坐标，确保在有效范围内
  watchEffect(() => {
    if (startedDrag.value) {
      transformX.value =
        preTransformX.value + Math.min(Math.max(dragRect.value.left, x.value), dragRect.value.right) - startX.value;
      transformY.value =
        preTransformY.value + Math.min(Math.max(dragRect.value.top, y.value), dragRect.value.bottom) - startY.value;
    }
  });

  // 通过计算样式移动弹窗
  const transformStyle = computed<CSSProperties>(() => {
    return {
      transform: `translate(${transformX.value}px, ${transformY.value}px)`,
    };
  });
</script>

<style lang="less" scoped>
.modal-content {
  padding: 0 24px;
  max-height: 500px; // 限制内容高度，避免超出视口
  overflow-y: auto; // 内容过多时滚动
}

.modal-footer {
  margin-top: 20px;
  padding: 16px 24px;
  border-top: 1px solid #f0f0f0;
}

.form-item-buttons {
  margin-top: auto;
  :deep(.ant-btn) {
    min-width: 80px; // 按钮最小宽度，避免文字换行
  }
}

:deep(.ant-modal-content) {
  padding-top: 0;
  border-radius: 8px; // 优化圆角，提升视觉体验
}

.draggable-modal {
  .title {
    padding: 16px 24px;
    margin: -24px -24px 16px;
    background: #fafafa;
    border-radius: 8px 8px 0 0;
    cursor: move;
    font-weight: 500;
    color: rgba(0, 0, 0, 0.88); // 加深标题颜色，提升可读性
  }
}

// 树形节点样式优化：确保层级显示清晰
:deep(.ant-tree-node-content-wrapper) {
  padding: 4px 0;
}
:deep(.ant-tree-indent-unit) {
  width: 16px; // 调整缩进宽度，避免层级过挤
}
</style>